package com.taobao.top.link;

import java.util.LinkedList;

public abstract class Pool<T> {
  private int           maxSize;
  private int           waitTimeout;
  private LinkedList<T> unused;
  private LinkedList<T> used;
  private Object        waiter;

  public Pool() {
    this(0, 0);
  }

  public Pool(int maxSize, int waitTimeout) {
    this.unused = new LinkedList<T>();
    this.used = new LinkedList<T>();
    this.waiter = new Object();
    this.maxSize = maxSize;
    this.waitTimeout = waitTimeout;
  }

  public int size() {
    // System.out.println(this.used.size() + "-" + this.unused.size());
    return this.used.size() + this.unused.size();
  }

  public T chekOut() throws Throwable {
    T t = this.get();

    if (t != null)
      return t;

    if (this.maxSize < 1 || this.size() < this.maxSize)
      return this.createNew();

    int i = 0;
    while (this.waitTimeout > 0 && i++ < this.waitTimeout) {
      synchronized (this.waiter) {
        try {
          this.waiter.wait(1);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
      t = this.get();

      if (t != null)
        return t;
    }

    return null;
  }

  public synchronized void checkIn(T t) {
    if (t == null)
      return;
    this.used.remove(t);
    this.unused.addLast(t);

    synchronized (this.waiter) {
      this.waiter.notifyAll();
    }
  }

  public abstract T create() throws Throwable;

  public abstract boolean validate(T t);

  private synchronized T get() {
    while (!this.unused.isEmpty()) {
      T t = this.unused.removeFirst();
      if (t == null)
        continue;
      if (this.validate(t)) {
        this.used.add(t);
        return t;
      }
    }
    return null;
  }

  private T createNew() throws Throwable {
    T t = this.create();
    this.used.addLast(t);
    return t;
  }
}
